knitr::opts_chunk$set(
    error     = TRUE,     # Ensures that error messages are being shown in the output
    fig.align = "center", # Ensures that all figures are aligned to the centre in the output
    message   = TRUE,     # Display messages generated by R
    warning   = TRUE,     # Display warnings generated by R
    autodep   = TRUE,     # Automatically detects dependencies between chunks and reruns dependent chunks when needed
    cache     = FALSE,    # Disables caching, meaning every time the document is knit, all chunks are re-executed
    results   = "markup", # Displays the output as normal formatted text
    echo      = TRUE     # Ensures that the R code itself is displayed in the document
    #dev       = "svg",    # Graphics output will be in Scalable Vector Graphics (SVG) format
    #out.width = "90%",    # Sets the width of the output image or plot to 90% of the available width 
  #out.extra = "keepaspectratio=true" # Adds extra options to the output, in this case, preserving the aspect ratio of the image or plot
)
# Maximum allowable size for globals in bytes that can be exported to the parallel workers
mib <- 9000*1024^2
options(future.globals.maxSize = mib)  # 1.5 GiB

1 Set up working environment

1.1 Load libraries & functions

# Load R libraries
library(here) # install.packages("here")
library(Seurat) # install.packages('Seurat')
library(hdf5r) # install.packages("hdf5r")
library(dplyr) # install.packages("dplyr")
library(ggplot2) # install.packages("ggplot2")
library(cowplot) # install.packages("cowplot")
library(glue) # install.packages("glue")
library(ggExtra) # install.packages("ggExtra")
library(DT) # install.packages('DT')
library(kableExtra) # install.packages("kableExtra")
library(glmGamPoi) # BiocManager::install("glmGamPoi")
library(harmony) # install.packages("harmony")
library(presto) # devtools::install_github("immunogenomics/presto")
library(openxlsx) # install.packages("openxlsx", dependencies = TRUE)
library(SingleR) # BiocManager::install("SingleR")
library(celldex) # BiocManager::install("celldex")
library(scrapper) # BiocManager::install("scrapper")
library(ggplotify) # install.packages("ggplotify")
library(viridis) # install.packages("viridis")
library(gridExtra) # install.packages("gridExtra")
library(openxlsx)
library(ggrepel)
library(dittoSeq)
library(ggplot2)
library(ggpubr)

# Source custom functions
source(here("code/R/functions/utils_v1.R"))

2 Configuration

# Custom colors
man_cols <- c("#86b0cc",  "#f3e65d", "#d5c1e7", "#eeb84c", "#82c39e", "#525252","#4d9f6b", "#b3939e", "#e76031", "#e9944b")
names(man_cols) <- c("B_cells", "NK_cells", "monocytes", "T_cells", "neutrophils", "megakaryocytes", "pDCs",
                     "plasma_cells", "progenitor_cells", "NKT_cells")

3 Import & pre-processing data

3.1 Load RDS file

seu <- readRDS(here("output/rds/blood_mouse_PPK_ONC_harmony_integrated_filtered_v2_20231_20236_annot.rds"))

3.2 Cluster annotation

seu@meta.data$cell_types <- as.character(seu@meta.data$cell_types)
seu@meta.data$cell_types[seu@meta.data$sub31 == "31_1"] <- "NKT_cells"
DimPlot(seu, group.by = "cell_types", reduction = "umap_harmony_SCT", label = TRUE, repel = TRUE) + scale_colour_manual(values = man_cols)
## Rasterizing points since number of points exceeds 100,000.
## To disable this behavior set `raster=FALSE`

4 Cell proportion

sce <- as.SingleCellExperiment(seu, assay = "RNA", slot = "data")
## Warning: The following arguments are not used: slot
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
## Found more than one class "package_version" in cache; using the first, from namespace 'SeuratObject'
## Also defined by 'alabaster.base'
p <- dittoBarPlot(sce, var = "cell_types_new", group.by = "sample_name")   +
    theme_classic() + theme(axis.title.x = element_blank()) + scale_x_discrete(limits = levels(seu@meta.data[["sample_name"]])) + rotate_x_text(angle = 90) + scale_fill_manual(values = man_cols)
## Error in .var_OR_get_meta_or_gene(var, object): cell_types_new is not a gene of the targeted assay(s), a metadata, nor equal in length to ncol('object')

5 Density plot of Cd3e+ T cells

Nebulosa::plot_density(seu, "Cd3e") + 
    facet_wrap(.~seu$sample_name, ncol = 6) + theme_void()

FeaturePlot(seu, features = "Cd3e", reduction = "umap_harmony_SCT", split.by = "sample_name") +
  patchwork::plot_layout(ncol = 6, nrow = 2)

6 Subselect NK and T cell clusters

seu_NKT <- subset(seu, subset = cell_types %in% c("T_cells", "NK_cells", "NKT_cells"))
DimPlot(seu_NKT, reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Cd3g", reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Cd79a", reduction = "umap_harmony_SCT")

DimPlot(seu, group.by = "sub31", reduction = "umap_harmony_SCT", label = TRUE, repel = TRUE)
## Rasterizing points since number of points exceeds 100,000.
## To disable this behavior set `raster=FALSE`

DimPlot(seu_NKT, group.by = "sub31", reduction = "umap_harmony_SCT", label = TRUE, repel = TRUE)

VlnPlot(seu_NKT, group.by = "sub31", features = "Cd79a")

seu_NKT <- subset(seu_NKT, subset = sub31 %ni% c("25", "31_3"))
FeaturePlot(seu_NKT, features = "Cd79a", reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Nkg7", reduction = "umap_harmony_SCT")

7 Re-clustering of subselected clusters

7.1 PCA

seu_NKT <- seu_NKT %>%
  RunPCA(
    npcs           = 30,
    pc.genes       = VariableFeatures(.),
    verbose        = FALSE,
    assay          = "SCT",
    reduction.name = 'pca',
    reduction.key  = 'pca_'
  )
## Warning: Number of dimensions changing from 50 to 30
# Plot PCA results
DimPlot(
  seu_NKT,
  reduction = "pca",
  group.by  = "orig.ident"
)

7.2 UMAP

seu_NKT <- seu_NKT %>%
  RunUMAP(
    reduction      = "pca",
    assay          = 'SCT',
    dims           = 1:30,
    reduction.name = "umap_SCT",
    reduction.key  = "umapSCT_"
  )
## 10:15:39 UMAP embedding parameters a = 0.9922 b = 1.112
## 10:15:39 Read 36917 rows and found 30 numeric columns
## 10:15:39 Using Annoy for neighbor search, n_neighbors = 30
## 10:15:39 Building Annoy index with metric = cosine, n_trees = 50
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 10:15:41 Writing NN index file to temp file /var/folders/8m/28zxygy92qn6h9ncp9l44ks00000gr/T//RtmpaiWd5b/file6ee17ef0bb0d
## 10:15:41 Searching Annoy index using 1 thread, search_k = 3000
## 10:15:48 Annoy recall = 100%
## 10:15:49 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
## 10:15:50 Initializing from normalized Laplacian + noise (using RSpectra)
## 10:15:51 Commencing optimization for 200 epochs, with 1598964 positive edges
## 10:15:51 Using rng type: pcg
## 10:16:01 Optimization finished
DimPlot(
  seu_NKT,
  reduction = "umap_SCT",
  group.by  = "sample_name"
) + ggtitle("Unintegrated UMAP-SCT")

7.3 Harmony

seu_NKT <- Seurat::IntegrateLayers(
  object         = seu_NKT,
  method         = HarmonyIntegration,
  orig.reduction = "pca",
  new.reduction  = 'harmony_SCT',
  assay          = "SCT",
  verbose        = FALSE
)
## Warning: Number of dimensions changing from 50 to 30
DimPlot(
  seu_NKT,
  reduction = "harmony_SCT",
  group.by  = "orig.ident"
) + ggtitle("Integrated Harmony-SCT")

7.4 UMAP-Harmony

# Run UMAP after Harmony integration
seu_NKT <- seu_NKT %>%
  RunUMAP(
    reduction      = "harmony_SCT",
    assay          = 'SCT',
    dims           = 1:30,
    reduction.name = "umap_harmony_SCT",
    reduction.key  = "umapharmonySCT_"
  )
## 10:16:25 UMAP embedding parameters a = 0.9922 b = 1.112
## 10:16:25 Read 36917 rows and found 30 numeric columns
## 10:16:25 Using Annoy for neighbor search, n_neighbors = 30
## 10:16:25 Building Annoy index with metric = cosine, n_trees = 50
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 10:16:27 Writing NN index file to temp file /var/folders/8m/28zxygy92qn6h9ncp9l44ks00000gr/T//RtmpaiWd5b/file6ee11113791e
## 10:16:27 Searching Annoy index using 1 thread, search_k = 3000
## 10:16:35 Annoy recall = 100%
## 10:16:36 Commencing smooth kNN distance calibration using 1 thread with target n_neighbors = 30
## 10:16:37 Initializing from normalized Laplacian + noise (using RSpectra)
## 10:16:37 Commencing optimization for 200 epochs, with 1668560 positive edges
## 10:16:37 Using rng type: pcg
## 10:16:48 Optimization finished
# Plot UMAP results
DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "sample_name"
) + ggtitle("Integrated Harmony-SCT")

DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "orig.ident",
  split.by = "sample_name",
  ncol = 6
) + ggtitle("Integrated Harmony-SCT")

8 Feature plots

FeaturePlot(seu_NKT, features = "Cd3e", reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Cd79a", reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Nkg7", reduction = "umap_harmony_SCT")

FeaturePlot(seu_NKT, features = "Hbb-bt", reduction = "umap_harmony_SCT")

9 Clusters identification

DefaultAssay(seu_NKT) <- "RNA"
seu_NKT <- seu_NKT %>%
  FindNeighbors(
    reduction    = "harmony_SCT",
    dims         = 1:30, 
    k.param      = 20,
    nn.method    = "annoy",
    n.trees      = 50,
    annoy.metric = "euclidean",
    nn.eps       = 0,
    verbose      = TRUE
  )
## Computing nearest neighbor graph
## Computing SNN
seu_NKT <- seu_NKT %>%
  FindClusters(
    algorithm   = 1,
    resolution  = 0.2,
    graph.name  = "SCT_snn",
    verbose     = FALSE,
    n.start     = 10,
    random.seed = 123
  )

seu_NKT <- seu_NKT %>%
  BuildClusterTree(
    reorder         = TRUE,
    reorder.numeric = TRUE,
    assay           = "RNA",
    dims            = 1:30,
    reduction       = "harmony_SCT",
    slot            = "data",
    verbose         = TRUE
  )
## Reordering identity classes and rebuilding tree
DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "tree.ident",
  label = TRUE
)

DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "cell_types",
  label = TRUE
)

DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "tree.ident",
  label = TRUE,
  split.by = "sample_name",
  ncol = 6
)

10 Reannotate NK/T cells clusters

seu_NKT@meta.data$T_clusters <- seu_NKT@meta.data$tree.ident
seu_NKT@meta.data$T_clusters[seu_NKT@meta.data$T_clusters == "1"] <- "NK_cells"
seu_NKT@meta.data$T_clusters[seu_NKT@meta.data$T_clusters %ni% c("NK_cells", "4")] <- "T_cells"
DimPlot(
  seu_NKT,
  reduction = "umap_harmony_SCT",
  group.by  = "T_clusters",
  label = TRUE
)

11 Cluster biomarkers

biomarkers <- wilcoxauc(seu_NKT, group_by = "T_clusters", seurat_assay = "RNA")

top_markers <- biomarkers %>%
  dplyr::filter(logFC > log(1.2) & padj < 0.001) %>%
  arrange(group, -logFC) %>%
  group_by(group) %>%
  slice_max(order_by = logFC, n = 5) %>%
  dplyr::select(feature, group, logFC, pval, padj, auc, statistic, avgExpr, pct_in, pct_out)
top_markers
FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = top_markers$feature[top_markers$group == "4"])

FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = c("Cd8a1", "Cd4", "Cd8b1", "Foxp3"))
## Warning: The following requested variables were not found: Cd8a1

Cluster 3 (nDNT3) accounted for 1.1% (108 cells) of nDNT cells and had 134 HEGs (Fig. 2b), such as cell membrane marker Klrc1, Klre1, Klrk1 and Nkg7, secreted protein Ccl4, Ccl5, Gzmb, Gzmk and Ifng https://www.sciencedirect.com/science/article/pii/S0896841121000615

FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = c("Ccl4", "Ccl5", "Gzmb", "Gzmk", "Ifng"))

As the biggest cluster (2618 cells, 83.8% of aDNT cells) (Fig. 4b and Table S9), aDNT0 cells specifically expressed cell membrane genes such as Cd160, Klrd1 and Ly6c2, secreted protein genes such as Ccl5, Ifng and Gzmb, and transcriptional factors such as Eomes, Nr4a1, Nr4a2 and Ikzf2 https://www.sciencedirect.com/science/article/pii/S0896841121000615

FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = c("Ccl5", "Ifng","Gzmb", "Eomes", "Nr4a1", "Nr4a2", "Ikzf2"))

As the biggest cluster 10,899 cells (86.3%) (Fig. 5b and Table S12), DNT0 cells conservatively and specifically express 38 genes (Fig. 5c and Table S12), including cell membrane genes: Cd160, Klrd1, Ly6c2, Ms4a4b and Nkg7, secreted protein genes: Ccl5 and Xcl1, and transcriptional factors: Klf2 and Ikzf2. https://www.sciencedirect.com/science/article/pii/S0896841121000615

FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = c("Cd160", "Klrd1", "Ly6c2", "Ms4a4b", "Nkg7", "Ccl5", "Xcl1", "Klf2", "Ikzf2"))

12 Cluster annotation using SingleR

This section uses SingleR, an automated cell type annotation tool, to predict cell identities in your Seurat object based on reference datasets from celldex. It performs annotation per cluster and visualises the results alongside UMAP plots.

# UMAP plot showing cluster identities
p_ident <- DimPlot(
  seu_NKT,
  label     = TRUE,
  repel     = TRUE,
  group.by  = "T_clusters",
  reduction = "umap_harmony_SCT"
) + NoLegend()

# Display the plot
print(p_ident)

We annotate clusters using three reference atlases from celldex: MouseRNAseq, DICE, and ImmGen.

# Extract RNA assay data to use as SingleR test input
expression <- GetAssayData(seu_NKT[["RNA"]], slot = "data")

# Use tree-based cluster identities for annotation
cluster_info <- seu_NKT@meta.data$T_clusters

# Load reference atlases for annotation
atlas_set <- list(
  "MRD"    = celldex::MouseRNAseqData(),
  "DICED"  = celldex::DatabaseImmuneCellExpressionData(),
  "IMMGEN" = celldex::ImmGenData()
)

# Loop over each reference set and label level
sapply(names(atlas_set), function(x) {
  
  for (label in c("label.main", "label.fine")) {
    
    # Run SingleR on clustered data
    prediction <- SingleR(
      test     = expression,
      ref      = atlas_set[[x]],
      labels   = atlas_set[[x]][[label]],
      clusters = cluster_info
    )

    # Plot annotation scores as a heatmap
    p_singleR <- plotScoreHeatmap(prediction, show_colnames = TRUE) %>% as.ggplot()

    # Display UMAP and annotation heatmap side-by-side
    p <- grid.arrange(grobs = list(p_ident, p_singleR), ncol = 2)
    p
    
  }
  
})

## $MRD
## NULL
## 
## $DICED
## NULL
## 
## $IMMGEN
## NULL

A large ILC1a cluster (cluster 1) and a small ILC1a-related cluster (cluster 7) that expressed IFNG, TBX21, KLRD1 and CD160 (Fig. 5a–c) were identified. https://pmc.ncbi.nlm.nih.gov/articles/PMC6685551/

FeaturePlot(seu_NKT, reduction = "umap_harmony_SCT", features = c("Tbx21", "Ifng", "Il7r", "Klrd1", "Cd160"))

seu_NKT@meta.data$T_clusters[seu_NKT@meta.data$T_clusters == "4"] <- "NK_ILC"
DimPlot(
  seu_NKT,
  label     = TRUE,
  repel     = TRUE,
  group.by  = "T_clusters",
  reduction = "umap_harmony_SCT"
) + NoLegend()

13 DEG in T cells

seu_T <- subset(seu_NKT, subset = T_clusters %in% "T_cells")
DimPlot(seu_T, reduction = "umap_harmony_SCT", label = TRUE)

FeaturePlot(seu_T, features = "Cd3e", reduction = "umap_harmony_SCT")

pairwise_comparisons <- list(
  
  "ONC_vs_UT_WB" = c("ONC_WB", "UT_WB"),
  "ONC_vs_UT_BM" = c("ONC_BM", "UT_BM"),
  
  "UT_vs_Sham_WB" = c("UT_WB", "Sham_WB"),
  "UT_vs_Sham_BM" = c("UT_BM", "Sham_BM"),
  
  "Sham_WB_vs_Naive_WB" = c("Sham_WB", "Naive_WB"),
  "Sham_WB_vs_Naive_BM" = c("Sham_BM", "Naive_BM")
  
)

wb <- createWorkbook()

for (i in names(pairwise_comparisons)) {
  
  deg_T <- wilcoxauc(seu_T, group_by = "sample_name", groups_use = pairwise_comparisons[[i]])
  
  addWorksheet(wb, sheetName = i)
  
  deg_T <- deg_T %>%
  filter(group ==  pairwise_comparisons[[i]][[1]]) %>%
    arrange(group, -logFC)
  
  writeData(wb, sheet = i, x = deg_T)
  

}

saveWorkbook(wb, here("output/deg_analysis/DEG_presto_ONC_UT_Sham_Naive_T_cells.xlsx"), overwrite = TRUE)

14 DEG in T and NK cells

DimPlot(seu_NKT, reduction = "umap_harmony_SCT", label = TRUE)

FeaturePlot(seu_NKT, features = "Cd3e", reduction = "umap_harmony_SCT")

pairwise_comparisons <- list(
  
  "ONC_vs_UT_WB" = c("ONC_WB", "UT_WB"),
  "ONC_vs_UT_BM" = c("ONC_BM", "UT_BM"),
  
  "UT_vs_Sham_WB" = c("UT_WB", "Sham_WB"),
  "UT_vs_Sham_BM" = c("UT_BM", "Sham_BM"),
  
  "Sham_WB_vs_Naive_WB" = c("Sham_WB", "Naive_WB"),
  "Sham_WB_vs_Naive_BM" = c("Sham_BM", "Naive_BM")
  
)

wb <- createWorkbook()

for (i in names(pairwise_comparisons)) {
  
  deg_NKT <- wilcoxauc(seu_NKT, group_by = "sample_name", groups_use = pairwise_comparisons[[i]])
  
  addWorksheet(wb, sheetName = i)
  
  deg_NKT <- deg_NKT %>%
  filter(group ==  pairwise_comparisons[[i]][[1]]) %>%
    arrange(group, -logFC)
  
  writeData(wb, sheet = i, x = deg_NKT)
  

}

saveWorkbook(wb, here("output/deg_analysis/DEG_presto_ONC_UT_Sham_Naive_NK_and_T_cells.xlsx"), overwrite = TRUE)

15 Export data

saveRDS(seu_NKT, here("output/rds/seu_NKT_blood_mouse_PPK_ONC_harmony_integrated_filtered_v2_20231_20236_annot.rds"))

16 Session information

This document was last rendered on:

## 2025-06-12 10:20:25.981372
Session Info
sessionInfo()
## R version 4.5.0 (2025-04-11)
## Platform: aarch64-apple-darwin20
## Running under: macOS Sonoma 14.7.6
## 
## Matrix products: default
## BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Pacific/Noumea
## tzcode source: internal
## 
## attached base packages:
## [1] stats4    stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] future_1.49.0               ggpubr_0.6.0                dittoSeq_1.20.0             ggrepel_0.9.6              
##  [5] gridExtra_2.3               viridis_0.6.5               viridisLite_0.4.2           ggplotify_0.1.2            
##  [9] scrapper_1.2.1              celldex_1.18.0              SingleR_2.10.0              SummarizedExperiment_1.38.1
## [13] Biobase_2.68.0              GenomicRanges_1.60.0        GenomeInfoDb_1.44.0         IRanges_2.42.0             
## [17] S4Vectors_0.46.0            BiocGenerics_0.54.0         generics_0.1.4              MatrixGenerics_1.20.0      
## [21] matrixStats_1.5.0           openxlsx_4.2.8              presto_1.0.0                data.table_1.17.4          
## [25] harmony_1.2.3               Rcpp_1.0.14                 glmGamPoi_1.20.0            kableExtra_1.4.0           
## [29] DT_0.33                     ggExtra_0.10.1              glue_1.8.0                  cowplot_1.1.3              
## [33] ggplot2_3.5.2               dplyr_1.1.4                 hdf5r_1.3.12                Seurat_5.3.0               
## [37] SeuratObject_5.1.0          sp_2.2-0                    here_1.0.1                 
## 
## loaded via a namespace (and not attached):
##   [1] fs_1.6.6                    spatstat.sparse_3.1-0       httr_1.4.7                  RColorBrewer_1.1-3         
##   [5] backports_1.5.0             tools_4.5.0                 sctransform_0.4.2           alabaster.base_1.8.0       
##   [9] R6_2.6.1                    HDF5Array_1.36.0            lazyeval_0.2.2              uwot_0.2.3                 
##  [13] rhdf5filters_1.20.0         withr_3.0.2                 progressr_0.15.1            cli_3.6.5                  
##  [17] textshaping_1.0.1           Cairo_1.6-2                 spatstat.explore_3.4-3      fastDummies_1.7.5          
##  [21] sass_0.4.10                 alabaster.se_1.8.0          labeling_0.4.3              mvtnorm_1.3-3              
##  [25] spatstat.data_3.1-6         ggridges_0.5.6              pbapply_1.7-2               systemfonts_1.2.3          
##  [29] yulab.utils_0.2.0           svglite_2.2.1               parallelly_1.45.0           rstudioapi_0.17.1          
##  [33] RSQLite_2.4.0               gridGraphics_0.5-1          ica_1.0-3                   spatstat.random_3.4-1      
##  [37] car_3.1-3                   zip_2.3.3                   Matrix_1.7-3                ggbeeswarm_0.7.2           
##  [41] abind_1.4-8                 lifecycle_1.0.4             yaml_2.3.10                 carData_3.0-5              
##  [45] rhdf5_2.52.0                SparseArray_1.8.0           BiocFileCache_2.16.0        Rtsne_0.17                 
##  [49] grid_4.5.0                  blob_1.2.4                  promises_1.3.3              ExperimentHub_2.16.0       
##  [53] crayon_1.5.3                miniUI_0.1.2                lattice_0.22-6              beachmat_2.24.0            
##  [57] KEGGREST_1.48.0             pillar_1.10.2               knitr_1.50                  future.apply_1.11.3        
##  [61] codetools_0.2-20            spatstat.univar_3.1-3       vctrs_0.6.5                 png_0.1-8                  
##  [65] gypsum_1.4.0                spam_2.11-1                 gtable_0.3.6                ks_1.15.1                  
##  [69] cachem_1.1.0                xfun_0.52                   S4Arrays_1.8.1              mime_0.13                  
##  [73] pracma_2.4.4                survival_3.8-3              pheatmap_1.0.12             SingleCellExperiment_1.30.1
##  [77] fitdistrplus_1.2-2          ROCR_1.0-11                 nlme_3.1-168                bit64_4.6.0-1              
##  [81] alabaster.ranges_1.8.0      filelock_1.0.3              RcppAnnoy_0.0.22            rprojroot_2.0.4            
##  [85] bslib_0.9.0                 irlba_2.3.5.1               vipor_0.4.7                 KernSmooth_2.23-26         
##  [89] colorspace_2.1-1            DBI_1.2.3                   ggrastr_1.0.2               tidyselect_1.2.1           
##  [93] bit_4.6.0                   compiler_4.5.0              curl_6.2.3                  httr2_1.1.2                
##  [97] BiocNeighbors_2.2.0         h5mread_1.0.1               xml2_1.3.8                  DelayedArray_0.34.1        
## [101] plotly_4.10.4               scales_1.4.0                lmtest_0.9-40               rappdirs_0.3.3             
## [105] stringr_1.5.1               digest_0.6.37               goftest_1.2-3               spatstat.utils_3.1-4       
## [109] alabaster.matrix_1.8.0      rmarkdown_2.29              RhpcBLASctl_0.23-42         XVector_0.48.0             
## [113] htmltools_0.5.8.1           pkgconfig_2.0.3             sparseMatrixStats_1.20.0    dbplyr_2.5.0               
## [117] fastmap_1.2.0               rlang_1.1.6                 htmlwidgets_1.6.4           UCSC.utils_1.4.0           
## [121] shiny_1.10.0                DelayedMatrixStats_1.30.0   jquerylib_0.1.4             farver_2.1.2               
## [125] zoo_1.8-14                  jsonlite_2.0.0              mclust_6.1.1                BiocParallel_1.42.1        
## [129] magrittr_2.0.3              Formula_1.2-5               GenomeInfoDbData_1.2.14     dotCall64_1.2              
## [133] patchwork_1.3.0             Rhdf5lib_1.30.0             ape_5.8-1                   reticulate_1.42.0          
## [137] stringi_1.8.7               alabaster.schemas_1.8.0     MASS_7.3-65                 AnnotationHub_3.16.0       
## [141] plyr_1.8.9                  parallel_4.5.0              listenv_0.9.1               deldir_2.0-4               
## [145] Biostrings_2.76.0           splines_4.5.0               tensor_1.5                  igraph_2.1.4               
## [149] spatstat.geom_3.4-1         ggsignif_0.6.4              RcppHNSW_0.6.0              reshape2_1.4.4             
## [153] BiocVersion_3.21.1          Nebulosa_1.18.0             evaluate_1.0.3              BiocManager_1.30.25        
## [157] httpuv_1.6.16               RANN_2.6.2                  tidyr_1.3.1                 purrr_1.0.4                
## [161] polyclip_1.10-7             scattermore_1.2             broom_1.0.8                 xtable_1.8-4               
## [165] RSpectra_0.16-2             rstatix_0.7.2               later_1.4.2                 tibble_3.2.1               
## [169] beeswarm_0.4.0              memoise_2.0.1               AnnotationDbi_1.70.0        cluster_2.1.8.1            
## [173] globals_0.18.0